package com.dustedpixels.jasmin.chips.z80.impl;

import com.dustedpixels.jasmin.chips.z80.Z80Context;
import com.dustedpixels.jasmin.chips.z80.implbase.Z80ImplBase;

/*
 *  Z80.java
 *
 *  Copyright 2004 Jan Bobrowski <jb@wizard.ae.krakow.pl>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  version 2 as published by the Free Software Foundation.
 */

/*
 *  Based on "The Undocumented Z80 Documented" by Sean Young
 */

public final class Z80VersionQAOP extends Z80ImplBase {
    interface Env {
        int m1(int addr);
        int mem(int addr);
        void mem(int addr, int v);
        int in(int port);
        void out(int port, int v);

        int mem16(int addr);
        void mem16(int addr, int v);

        void cont(int addr, int n); // possible contention on T..T+n-1
    }

    private final Env env;

    Z80VersionQAOP(Env env) {
        this.env = env;
    }

    Z80VersionQAOP(final Z80Context context) {
        this.env = new Env() {
            public void cont(int addr, int n) {}
            public int in(int port) {return context.in((short) port) & 0xFF;}
            public void out(int port, int v) {context.out((short) port, (byte) v);}
            public int m1(int addr) {return context.peek((short) addr) & 0xFF;}
            public int mem(int addr) {return context.peek((short) addr) & 0xFF;}
            public void mem(int addr, int v) {context.poke((short) addr, (byte) v);}
            public int mem16(int addr) {
                return (context.peek((short) addr) & 0xFF) |
                       ((context.peek((short) (addr+1)) & 0xFF) << 8);
            }

            public void mem16(int addr, int v) {
                context.poke((short) addr, (byte) v);
                context.poke((short) (addr+1), (byte) (v >>> 8));
            }
        };
    }

    private int PC, SP;
    private int I, R, R7;
    private int A, B, C, D, E, HL;
    private int A_, B_, C_, D_, E_, HL_;
    private int IX, IY;
    private int ir; // hidden register

    private int Ff, Fr, Fa, Fb;
    private int Ff_, Fr_, Fa_, Fb_;

/*
   Z: Fr==0
   P: parity of Fr&0xFF
 P/V: X ? P : V
        FEDCBA98 76543210
    Ff  .......C S.5.3...
    Fr  ........ V..H....
    Fa  .......X V..H....
    Fb  ...H..N. V..H....
*/
    static final int FC = 0x01;
    static final int FN = 0x02;
    static final int FP = 0x04;
    static final int F3 = 0x08;
    static final int FH = 0x10;
    static final int F5 = 0x20;
    static final int FZ = 0x40;
    static final int FS = 0x80;
    static final int F53 = 0x28;
    
    private int flags() {
        int f = Ff&(FS|F53) | Ff>>8&FC;     // S.5.3..C
        int ra = Fr ^ Fa;
        int u = Fb >> 8;
        if(Fr == 0) f |= FZ;            // .Z......
        f |= u & FN;                // ......N.
        f |= (ra ^ Fb ^ u) & FH;        // ...H....
        if((Fa&~0xFF)==0)
            f |= (ra & (Fb ^ Fr))>>5 & FP;  // .....V..
        else {
            int p = Fr;
            p ^= p>>4;
            p ^= p<<2;
            p = ~p ^ p>>1;
            f |= p & FP;            // .....P..
        }
        return f;
    }

    private void flags(int f) {
        Ff = f&(FS|F53) | f<<8&0x100;
        Fr = ~f&FZ;
        Fa = Fb = (f&FP)<<5;
        Fa |= f&FH;
        Fb |= (f&FN)!=0 ? ~0x80 : 0;
    }

    int a() {return A;}
    int f() {return flags();}
    int bc() {return B<<8|C;}
    int de() {return D<<8|E;}
    int hl() {return HL;}
    int ix() {return IX;}
    int iy() {return IY;}
    int pc() {return PC;}
    int sp() {return SP;}
    int af() {return A<<8 | flags();}

    void a(int v) {A = v;}
    void f(int v) {flags(v);}
    void bc(int v) {C=v&0xFF; B=v>>>8;}
    void de(int v) {E=v&0xFF; D=v>>>8;}
    void hl(int v) {HL = v;}
    void ix(int v) {IX = v;}
    void iy(int v) {IY = v;}
    void pc(int v) {PC = v;}
    void sp(int v) {SP = v;}
    void af(int v) {A = v>>>8; flags(v&0xFF);}

    void i(int v) {I = v;}
    void r(int v) {R=v; R7=v&0x80;}
    void im(int v) {v&=3; if(v!=0) v++; IM = (byte)v;}
    void iff(int v) {IFF = (byte)v;}
    void ei(boolean v) {IFF = (byte)(v?3:0);}

    int i() {return I;}
    int r() {return R&0x7F | R7;}
    boolean ei() {return (IFF&1)!=0;}

    int ticks;
    int ticks_limit;

    void exx() {
        int tmp;
        tmp = B_; B_ = B; B = tmp;
        tmp = C_; C_ = C; C = tmp;
        tmp = D_; D_ = D; D = tmp;
        tmp = E_; E_ = E; E = tmp;
        tmp = HL_; HL_ = HL; HL = tmp;
    }
    
    void ex_af() {
        int tmp = A_; A_ = A; A = tmp;
        tmp = Ff_; Ff_ = Ff; Ff = tmp;
        tmp = Fr_; Fr_ = Fr; Fr = tmp;
        tmp = Fa_; Fa_ = Fa; Fa = tmp;
        tmp = Fb_; Fb_ = Fb; Fb = tmp;
    }

    public void push(int v) {
        SP = SP-2 & 0xFFFF;
        ticks++;
        env.mem16(SP, v);
        ticks += 6;
    }
    
    int pop() {
        int v = env.mem16(SP);
        SP = SP+2 & 0xFFFF;
        ticks += 6;
        return v;
    }

    private void add(int b)
    {
        int r = A + b;
        Fa = A; Fb = b; Ff = r;
        A = Fr = r&0xFF;
    }

    private void adc(int b)
    {
        int r = A + b + (Ff>>8 & FC);
        Fa = A; Fb = b; Ff = r;
        A = Fr = r&0xFF;
    }
    
    private void sub(int b)
    {
        int r = A - b;
        Fa = A; Fb = ~b; Ff = r;
        A = Fr = r&0xFF;
    }

    private void sbc(int b)
    {
        int r = A - b - (Ff>>8 & FC);
        Fa = A; Fb = ~b; Ff = r;
        A = Fr = r&0xFF;
    }

    private void cp(int b)
    {
        int r = A - b;
        Fa = A; Fb = ~b;
        Ff = r&~F53 | b&F53;
        Fr = r&0xFF;
    }

    private void and(int b)
    {
        int r = A & b;
        A = Ff = Fr = r;
        Fa = ~r; Fb = 0;
    }

    private void or(int b)
    {
        int r = A | b;
        A = Ff = Fr = r;
        Fa = r|0x100; Fb = 0;
    }

    private void xor(int b)
    {
        int r = A ^ b;
        A = Ff = Fr = r;
        Fa = r|0x100; Fb = 0;
    }
    
    private void cpl()
    {
        A = A^0xFF;
        Ff = Ff&~F53 | A&F53;
        Fb |= ~0x80; Fa = Fa&~FH | ~Fr&FH; // set H, N
    }

    private int inc(int v)
    {
        int r = v+1 & 0xFF;
        Fa = v; Fb = 0; Fr = r;
        Ff = Ff&~0xFF | r;
        return r;
    }

    private int dec(int v)
    {
        int r = v-1 & 0xFF;
        Fa = v; Fb = -1; Fr = r;
        Ff = Ff&~0xFF | r;
        return r;
    }
    
    private void bit(int n, int v)
    {
        Ff = Ff&~0xFF | (v &= 1<<n);
        Fa = ~(Fr = v); Fb = 0;
    }
    
    private void f_szh0n0p(int r)
    {
        // SZ5H3PNC
        // xxx0xP0.
        Ff = Ff&~0xFF | r;
        Fr = r; Fa = r|0x100; Fb = 0;
    }

    private void f_h0n0_c35(int v)
    {
        Ff = Ff&0xD7 | v&0x128;
        Fb &= 0x80; Fa = Fa&~FH | Fr&FH; // reset H, N
    }

    private int shifter(int o, int v)
    {
        int b;
        if((o&1)==0) {
            v <<= 1;
            if(o<=2) b = (o==0 ? v : Ff) >> 8;
            else b = o>>1;
            v |= b&1;
            Ff = v;
            v &= 0xFF;
        } else {
            b = 0;
            switch(o) {
                case 1: b = v<<8; break;
                case 3: b = Ff; break;
                case 5: b = v<<1; break;
            }
            v |= b&0x100;
            Ff = v<<8;
            v >>>= 1;
            Ff |= v;
        }
        Fr = v; Fa = v|0x100; Fb = 0;
        return v;
    }

    private int add16(int a, int b)
    {
        int r = a + b;
        int h = (r ^ a ^ b)>>8 & 0x10;
        Fb &= 0x80;
        Fa = Fa&~0x10 | (Fr ^ h)&0x10;
        Ff = Ff&~(0x100|F53) | r>>8 & (0x100|F53);
        ir = a;
        ticks += 7;
        return r&0xFFFF;
    }

    private void adc_hl(int b)
    {
        int r = HL + b + (Ff>>8 & FC);
        Ff = r>>8;
        Fa = HL>>8; Fb = b>>8;
        r &= 0xFFFF;
        Fr = r>>8 | r<<8;
        HL = r;
        ticks += 7;
    }

    private void sbc_hl(int b)
    {
        int r = HL - b - (Ff>>8 & FC);
        Ff = r>>8;
        Fa = HL>>8; Fb = ~(b>>8);
        r &= 0xFFFF;
        Fr = r>>8 | r<<8;
        HL = r;
        ticks += 7;
    }
    
    private void scf_ccf(int v)
    {
        Ff = Ff&0xD7 | v | A&0x28;
        Fb &= 0x80;
        Fa = (Fa|FH) ^ Fr&FH ^ v>>>4;
    }

    private int getd(int xy)
    {
        int d = env.mem(PC);
        PC = PC+1 & 0xFFFF;
        ticks += 8;
        return ir = xy+(byte)d & 0xFFFF;
    }

    private int imm8()
    {
        int v = env.mem(PC);
        PC = PC+1 & 0xFFFF;
        ticks += 3;
        return v;
    }

    private int imm16()
    {
        int v = env.mem16(PC);
        PC = PC+2 & 0xFFFF;
        ticks += 6;
        return v;
    }

    /* instructions */

    private void daa()
    {
        int h = (Fr ^ Fa ^ Fb ^ Fb>>8) & FH;

        int d = 0;
        if((A | Ff&0x100) > 0x99) d = 0x160;
        if((A&0xF | h) > 9) d += 6;

        Fa = A | 0x100; // parity
        if((Fb & 0x200)==0)
            A += (Fb = d);
        else {
            A -= d; Fb = ~d;
        }
        A &= 0xFF;
        Ff = A | d&0x100;
        Fr = A;
    }

    private void rrd()
    {
        int v = env.mem(HL) | A<<8;
        ticks += 7;
        f_szh0n0p(A = A&0xF0 | v&0x0F);
        v = v>>>4 & 0xFF;
        env.mem(HL, v);
        ticks += 3;
    }

    private void rld()
    {
        int v = env.mem(HL)<<4 | A&0x0F;
        ticks += 7;
        f_szh0n0p(A = A&0xF0 | v>>>8);
        v &= 0xFF;
        env.mem(HL, v);
        ticks += 3;
    }

    private void ld_a_ir(int v)
    {
        A = v;
        Ff = Ff&~0xFF | v;
        Fr = v==0 ? 0 : 1;
        Fa = Fb = IFF<<6 & 0x80;
        ticks++;
    }

    private void jp(boolean y)
    {
        int a = imm16();
        if(y) PC = a;
    }

    private void jr(boolean y)
    {
        int pc = PC;
        byte d = (byte)env.mem(pc); ticks += 3;
        if(y) {env.cont(pc,5); ticks += 5; ir = pc = pc+d+1 & 0xFFFF;}
        else pc = pc+1 & 0xFFFF;
        PC = pc;
    }

    private void call(boolean y)
    {
        int a = imm16();
        if(y) {env.cont(PC,1); push(PC); ir = PC = a;}
    }

    private void halt()
    {
        halted = true;
        int n = ticks_limit-ticks+3 >> 2;
        if(n>0) {
            R+=n; ticks+=4*n;
        }
    }

    private void ldir(int i, boolean r)
    {
        int hl = HL, de = de(), bc = (bc()-1 & 0xFFFF)+1;
        int v, pc = PC-2 & 0xFFFF;
        for(;;) {
            v = env.mem(hl); hl = hl+i & 0xFFFF;
            ticks += 3;
            env.mem(de, v);
            ticks += 3;
            env.cont(v=de, 2); de = de+i & 0xFFFF;
            ticks += 2;
            if(--bc==0 || !r) break;
            if(ticks>=ticks_limit || de==pc || de==pc+1) {
                PC = pc;
                env.cont(v, 5);
                ticks += 5;
                break;
            }
            ticks += 13;
        }
        HL = hl; de(de); bc(bc);

        if(Fr!=0) Fr = 1; // keep Z
        Fa = Fb = bc!=0 ? 0x80 : 0;
        v += A;
        Ff = Ff&~F53 | v&F3 | v<<4&F5;
    }

    private void cpir(int i, boolean r)
    {
        int b = env.mem(HL);
        int v = A-b & 0xFF;
        HL = HL+i & 0xFFFF;

        Fr = v & ~0x80 | v>>>7;
        Fb = ~b & ~0x80;
        Fa = A & ~0x80;

        ticks += 8;
        int bc = bc() - 1;
        if(bc!=0) {
            Fa |= 0x80;
            Fb |= 0x80;
            if(r && v!=0) {
                PC = PC-2 & 0xFFFF;
                ticks += 5;
            }
            bc &= 0xFFFF;
        }
        bc(bc);

        Ff = Ff&~0xFF | v&~F53;
        if(((v ^ b ^ A)&FH) != 0) v--;
        Ff |= v<<4&0x20 | v&8;
    }

    private void inir_otir(int op)
    {
        // 101rd01o
        int v, d, m;
        HL = (m = HL) + (d = 1 - (op>>2 & 2));
        int b = B-1 & 0xFF;
        int k;
        ticks++;
        if((op&1)==0) {
            v = env.in(b<<8|C);
            ticks += 4;
            env.mem(m, v);
            ticks += 3;
            k = (Ff>>8&1) + d;
        } else {
            v = env.mem(m);
            ticks += 3;
            env.out(B<<8|C, v);
            ticks += 4;
            k = HL;
        }
        k = (k&0xFF) + v;
        if(b!=0 && op>=0xB0) {
            PC = PC-2 & 0xFFFF;
            ticks += 5;
        }
        Fr = B = b;
        Ff = b | k&0x100;
        Fb = (k & 0x100)<<4 | v<<2 & 0x200; // H,N
        k = k&7 ^ b; k ^= k<<4; k ^= k<<2; k ^= k<<1;
        Fb |= (k^b) & 0x80; // P
        Fa = Fb;
    }

    void execute()
    {
        if(halted) {
            halt();
            return;
        }
        do {
            int c = env.m1(PC); PC = PC+1 & 0xFFFF;
            ticks += 4; R++;
            switch(c) {
// -------------- >8
// case 0x00: break;
 case 0x08: ex_af(); break;
 case 0x10: {ticks++; int pc; byte d=(byte)env.mem(pc=PC); ticks+=3;
    if((B=B-1&0xFF)>0) {env.cont(pc,5); ticks+=5; pc+=d;}
    PC=pc+1&0xFFFF;} break;
 case 0x18: {byte d=(byte)env.mem(PC); ticks+=3; env.cont(PC,5); ticks+=5;
    PC=ir=PC+1+d&0xFFFF;} break;
 case 0x01: {int v=imm16(); B=v>>>8; C=v&0xFF;} break;
 case 0x03: {int v=(B<<8|C)+1&0xFFFF; B=v>>>8; C=v&0xFF;} ticks+=2; break;
 case 0x09: HL=add16(HL,B<<8|C); break;
 case 0x0B: {int v=(B<<8|C)-1&0xFFFF; B=v>>>8; C=v&0xFF;} ticks+=2; break;
 case 0x11: {int v=imm16(); D=v>>>8; E=v&0xFF;} break;
 case 0x13: {int v=(D<<8|E)+1&0xFFFF; D=v>>>8; E=v&0xFF;} ticks+=2; break;
 case 0x19: HL=add16(HL,D<<8|E); break;
 case 0x1B: {int v=(D<<8|E)-1&0xFFFF; D=v>>>8; E=v&0xFF;} ticks+=2; break;
 case 0x21: HL=imm16(); break;
 case 0x23: HL=HL+1&0xFFFF; ticks+=2; break;
 case 0x29: HL=add16(HL,HL); break;
 case 0x2B: HL=HL-1&0xFFFF; ticks+=2; break;
 case 0x31: SP=imm16(); break;
 case 0x33: SP=SP+1&0xFFFF; ticks+=2; break;
 case 0x39: HL=add16(HL,SP); break;
 case 0x3B: SP=SP-1&0xFFFF; ticks+=2; break;
 case 0x02: env.mem(B<<8|C,A); ticks+=3; break;
 case 0x0A: A=env.mem(B<<8|C); ticks+=3; break;
 case 0x12: env.mem(D<<8|E,A); ticks+=3; break;
 case 0x1A: A=env.mem(D<<8|E); ticks+=3; break;
 case 0x22: env.mem16(imm16(),HL); ticks+=6; break;
 case 0x2A: HL=env.mem16(imm16()); ticks+=6; break;
 case 0x32: env.mem(imm16(),A); ticks+=3; break;
 case 0x3A: A=env.mem(imm16()); ticks+=3; break;
 case 0x04: B=inc(B); break;
 case 0x05: B=dec(B); break;
 case 0x06: B=imm8(); break;
 case 0x0C: C=inc(C); break;
 case 0x0D: C=dec(C); break;
 case 0x0E: C=imm8(); break;
 case 0x14: D=inc(D); break;
 case 0x15: D=dec(D); break;
 case 0x16: D=imm8(); break;
 case 0x1C: E=inc(E); break;
 case 0x1D: E=dec(E); break;
 case 0x1E: E=imm8(); break;
 case 0x24: HL=HL&0xFF|inc(HL>>>8)<<8; break;
 case 0x25: HL=HL&0xFF|dec(HL>>>8)<<8; break;
 case 0x26: HL=HL&0xFF|imm8()<<8; break;
 case 0x2C: HL=HL&0xFF00|inc(HL&0xFF); break;
 case 0x2D: HL=HL&0xFF00|dec(HL&0xFF); break;
 case 0x2E: HL=HL&0xFF00|imm8(); break;
 case 0x34: {int v=inc(env.mem(HL)); ticks+=4; env.mem(HL,v); ticks+=3;} break;
 case 0x35: {int v=dec(env.mem(HL)); ticks+=4; env.mem(HL,v); ticks+=3;} break;
 case 0x36: env.mem(HL,imm8()); ticks+=3; break;
 case 0x3C: A=inc(A); break;
 case 0x3D: A=dec(A); break;
 case 0x3E: A=imm8(); break;
 case 0x20: jr(Fr!=0); break;
 case 0x28: jr(Fr==0); break;
 case 0x30: jr((Ff&0x100)==0); break;
 case 0x38: jr((Ff&0x100)!=0); break;
 case 0x07: {int a=A<<1|A>>>7; f_h0n0_c35(a); A=a&0xFF;} break;
 case 0x0F: {int a=A>>>1; f_h0n0_c35(a|A<<8); A=a|A<<7&0xFF;} break;
 case 0x17: {int a=A<<1; A=a&0xFF|Ff>>>8&1; f_h0n0_c35(a);} break;
 case 0x1F: {int a=A; A=(a|Ff&0x100)>>>1; f_h0n0_c35(A|a<<8);} break;
 case 0x27: daa(); break;
 case 0x2F: cpl(); break;
 case 0x37: scf_ccf(0x100); break;
 case 0x3F: scf_ccf(~Ff&0x100); break;
// case 0x40: break;
 case 0x41: B=C; break;
 case 0x42: B=D; break;
 case 0x43: B=E; break;
 case 0x44: B=HL>>>8; break;
 case 0x45: B=HL&0xFF; break;
 case 0x46: B=env.mem(HL); ticks+=3; break;
 case 0x47: B=A; break;
 case 0x48: C=B; break;
// case 0x49: break;
 case 0x4A: C=D; break;
 case 0x4B: C=E; break;
 case 0x4C: C=HL>>>8; break;
 case 0x4D: C=HL&0xFF; break;
 case 0x4E: C=env.mem(HL); ticks+=3; break;
 case 0x4F: C=A; break;
 case 0x50: D=B; break;
 case 0x51: D=C; break;
// case 0x52: break;
 case 0x53: D=E; break;
 case 0x54: D=HL>>>8; break;
 case 0x55: D=HL&0xFF; break;
 case 0x56: D=env.mem(HL); ticks+=3; break;
 case 0x57: D=A; break;
 case 0x58: E=B; break;
 case 0x59: E=C; break;
 case 0x5A: E=D; break;
// case 0x5B: break;
 case 0x5C: E=HL>>>8; break;
 case 0x5D: E=HL&0xFF; break;
 case 0x5E: E=env.mem(HL); ticks+=3; break;
 case 0x5F: E=A; break;
 case 0x60: HL=HL&0xFF|B<<8; break;
 case 0x61: HL=HL&0xFF|C<<8; break;
 case 0x62: HL=HL&0xFF|D<<8; break;
 case 0x63: HL=HL&0xFF|E<<8; break;
// case 0x64: break;
 case 0x65: HL=HL&0xFF|(HL&0xFF)<<8; break;
 case 0x66: HL=HL&0xFF|env.mem(HL)<<8; ticks+=3; break;
 case 0x67: HL=HL&0xFF|A<<8; break;
 case 0x68: HL=HL&0xFF00|B; break;
 case 0x69: HL=HL&0xFF00|C; break;
 case 0x6A: HL=HL&0xFF00|D; break;
 case 0x6B: HL=HL&0xFF00|E; break;
 case 0x6C: HL=HL&0xFF00|HL>>>8; break;
// case 0x6D: break;
 case 0x6E: HL=HL&0xFF00|env.mem(HL); ticks+=3; break;
 case 0x6F: HL=HL&0xFF00|A; break;
 case 0x70: env.mem(HL,B); ticks+=3; break;
 case 0x71: env.mem(HL,C); ticks+=3; break;
 case 0x72: env.mem(HL,D); ticks+=3; break;
 case 0x73: env.mem(HL,E); ticks+=3; break;
 case 0x74: env.mem(HL,HL>>>8); ticks+=3; break;
 case 0x75: env.mem(HL,HL&0xFF); ticks+=3; break;
 case 0x76: halt(); break;
 case 0x77: env.mem(HL,A); ticks+=3; break;
 case 0x78: A=B; break;
 case 0x79: A=C; break;
 case 0x7A: A=D; break;
 case 0x7B: A=E; break;
 case 0x7C: A=HL>>>8; break;
 case 0x7D: A=HL&0xFF; break;
 case 0x7E: A=env.mem(HL); ticks+=3; break;
// case 0x7F: break;
 case 0x80: add(B); break;
 case 0x81: add(C); break;
 case 0x82: add(D); break;
 case 0x83: add(E); break;
 case 0x84: add(HL>>>8); break;
 case 0x85: add(HL&0xFF); break;
 case 0x86: add(env.mem(HL)); ticks+=3; break;
 case 0x87: add(A); break;
 case 0x88: adc(B); break;
 case 0x89: adc(C); break;
 case 0x8A: adc(D); break;
 case 0x8B: adc(E); break;
 case 0x8C: adc(HL>>>8); break;
 case 0x8D: adc(HL&0xFF); break;
 case 0x8E: adc(env.mem(HL)); ticks+=3; break;
 case 0x8F: adc(A); break;
 case 0x90: sub(B); break;
 case 0x91: sub(C); break;
 case 0x92: sub(D); break;
 case 0x93: sub(E); break;
 case 0x94: sub(HL>>>8); break;
 case 0x95: sub(HL&0xFF); break;
 case 0x96: sub(env.mem(HL)); ticks+=3; break;
 case 0x97: sub(A); break;
 case 0x98: sbc(B); break;
 case 0x99: sbc(C); break;
 case 0x9A: sbc(D); break;
 case 0x9B: sbc(E); break;
 case 0x9C: sbc(HL>>>8); break;
 case 0x9D: sbc(HL&0xFF); break;
 case 0x9E: sbc(env.mem(HL)); ticks+=3; break;
 case 0x9F: sbc(A); break;
 case 0xA0: and(B); break;
 case 0xA1: and(C); break;
 case 0xA2: and(D); break;
 case 0xA3: and(E); break;
 case 0xA4: and(HL>>>8); break;
 case 0xA5: and(HL&0xFF); break;
 case 0xA6: and(env.mem(HL)); ticks+=3; break;
 case 0xA7: and(A); break;
 case 0xA8: xor(B); break;
 case 0xA9: xor(C); break;
 case 0xAA: xor(D); break;
 case 0xAB: xor(E); break;
 case 0xAC: xor(HL>>>8); break;
 case 0xAD: xor(HL&0xFF); break;
 case 0xAE: xor(env.mem(HL)); ticks+=3; break;
 case 0xAF: xor(A); break;
 case 0xB0: or(B); break;
 case 0xB1: or(C); break;
 case 0xB2: or(D); break;
 case 0xB3: or(E); break;
 case 0xB4: or(HL>>>8); break;
 case 0xB5: or(HL&0xFF); break;
 case 0xB6: or(env.mem(HL)); ticks+=3; break;
 case 0xB7: or(A); break;
 case 0xB8: cp(B); break;
 case 0xB9: cp(C); break;
 case 0xBA: cp(D); break;
 case 0xBB: cp(E); break;
 case 0xBC: cp(HL>>>8); break;
 case 0xBD: cp(HL&0xFF); break;
 case 0xBE: cp(env.mem(HL)); ticks+=3; break;
 case 0xBF: cp(A); break;
 case 0xDD:
 case 0xFD: group_xy(c); break;
 case 0xCB: group_cb(); break;
 case 0xED: group_ed(); break;
 case 0xC0: ticks++; if(Fr!=0) ir=PC=pop(); break;
 case 0xC2: jp(Fr!=0); break;
 case 0xC4: call(Fr!=0); break;
 case 0xC8: ticks++; if(Fr==0) ir=PC=pop(); break;
 case 0xCA: jp(Fr==0); break;
 case 0xCC: call(Fr==0); break;
 case 0xD0: ticks++; if((Ff&0x100)==0) ir=PC=pop(); break;
 case 0xD2: jp((Ff&0x100)==0); break;
 case 0xD4: call((Ff&0x100)==0); break;
 case 0xD8: ticks++; if((Ff&0x100)!=0) ir=PC=pop(); break;
 case 0xDA: jp((Ff&0x100)!=0); break;
 case 0xDC: call((Ff&0x100)!=0); break;
 case 0xE0: ticks++; if((flags()&FP)==0) ir=PC=pop(); break;
 case 0xE2: jp((flags()&FP)==0); break;
 case 0xE4: call((flags()&FP)==0); break;
 case 0xE8: ticks++; if((flags()&FP)!=0) ir=PC=pop(); break;
 case 0xEA: jp((flags()&FP)!=0); break;
 case 0xEC: call((flags()&FP)!=0); break;
 case 0xF0: ticks++; if((Ff&FS)==0) ir=PC=pop(); break;
 case 0xF2: jp((Ff&FS)==0); break;
 case 0xF4: call((Ff&FS)==0); break;
 case 0xF8: ticks++; if((Ff&FS)!=0) ir=PC=pop(); break;
 case 0xFA: jp((Ff&FS)!=0); break;
 case 0xFC: call((Ff&FS)!=0); break;
 case 0xC1: {int v=pop(); B=v>>8; C=v&0xFF;} break;
 case 0xC5: push(B<<8|C); break;
 case 0xD1: {int v=pop(); D=v>>8; E=v&0xFF;} break;
 case 0xD5: push(D<<8|E); break;
 case 0xE1: HL=pop(); break;
 case 0xE5: push(HL); break;
 case 0xF1: af(pop()); break;
 case 0xF5: push(A<<8|flags()); break;
 case 0xC3: PC=imm16(); break;
 case 0xC6: add(imm8()); break;
 case 0xCE: adc(imm8()); break;
 case 0xD6: sub(imm8()); break;
 case 0xDE: sbc(imm8()); break;
 case 0xE6: and(imm8()); break;
 case 0xEE: xor(imm8()); break;
 case 0xF6: or(imm8()); break;
 case 0xFE: cp(imm8()); break;
 case 0xC9: ir=PC=pop(); break;
 case 0xCD: {int a=imm16(); env.cont(PC,1); push(PC); ir=PC=a;} break;
 case 0xD3: env.out(imm8()|A<<8,A); ticks+=4; break;
 case 0xDB: A=env.in(imm8()|A<<8); ticks+=4; break;
 case 0xD9: exx(); break;
 case 0xE3: {int v=env.mem16(SP); ticks+=7;
    env.mem16(SP,HL); HL=v;} ticks+=8; break;
 case 0xE9: PC=HL; break;
 case 0xEB: {int v=HL; HL=D<<8|E; D=v>>>8; E=v&0xFF;} break;
 case 0xF3: IFF=0; break;
 case 0xFB: IFF=3; break;
 case 0xF9: SP=HL; ticks+=2; break;
 case 0xC7:
 case 0xCF:
 case 0xD7:
 case 0xDF:
 case 0xE7:
 case 0xEF:
 case 0xF7:
 case 0xFF: push(PC); PC=c-199; break;
// -------------- >8
            }
        } while(ticks_limit - ticks > 0);
    }
    
    private void group_xy(int c0)
    {
        for(;;) {
            int xy = c0==0xDD ? IX : IY;
            int c = env.m1(PC); PC = PC+1 & 0xFFFF;
            ticks += 4; R++;
            switch(c) {
// -------------- >8
// case 0x00: break;
 case 0x08: ex_af(); break;
 case 0x10: ticks++; jr((B=B-1&0xFF)>0); break;
 case 0x18: jr(true); break;
 case 0x01: {int v=imm16(); B=v>>>8; C=v&0xFF;} break;
 case 0x03: {int v=(B<<8|C)+1&0xFFFF; B=v>>>8; C=v&0xFF;} ticks+=2; break;
 case 0x09: xy=add16(xy,B<<8|C); break;
 case 0x0B: {int v=(B<<8|C)-1&0xFFFF; B=v>>>8; C=v&0xFF;} ticks+=2; break;
 case 0x11: {int v=imm16(); D=v>>>8; E=v&0xFF;} break;
 case 0x13: {int v=(D<<8|E)+1&0xFFFF; D=v>>>8; E=v&0xFF;} ticks+=2; break;
 case 0x19: xy=add16(xy,D<<8|E); break;
 case 0x1B: {int v=(D<<8|E)-1&0xFFFF; D=v>>>8; E=v&0xFF;} ticks+=2; break;
 case 0x21: xy=imm16(); break;
 case 0x23: xy=xy+1&0xFFFF; ticks+=2; break;
 case 0x29: xy=add16(xy,xy); break;
 case 0x2B: xy=xy-1&0xFFFF; ticks+=2; break;
 case 0x31: SP=imm16(); break;
 case 0x33: SP=SP+1&0xFFFF; ticks+=2; break;
 case 0x39: xy=add16(xy,SP); break;
 case 0x3B: SP=SP-1&0xFFFF; ticks+=2; break;
 case 0x02: env.mem(B<<8|C,A); ticks+=3; break;
 case 0x0A: A=env.mem(B<<8|C); ticks+=3; break;
 case 0x12: env.mem(D<<8|E,A); ticks+=3; break;
 case 0x1A: A=env.mem(D<<8|E); ticks+=3; break;
 case 0x22: env.mem16(imm16(),xy); ticks+=6; break;
 case 0x2A: xy=env.mem16(imm16()); ticks+=6; break;
 case 0x32: env.mem(imm16(),A); ticks+=3; break;
 case 0x3A: A=env.mem(imm16()); ticks+=3; break;
 case 0x04: B=inc(B); break;
 case 0x05: B=dec(B); break;
 case 0x06: B=imm8(); break;
 case 0x0C: C=inc(C); break;
 case 0x0D: C=dec(C); break;
 case 0x0E: C=imm8(); break;
 case 0x14: D=inc(D); break;
 case 0x15: D=dec(D); break;
 case 0x16: D=imm8(); break;
 case 0x1C: E=inc(E); break;
 case 0x1D: E=dec(E); break;
 case 0x1E: E=imm8(); break;
 case 0x24: xy=xy&0xFF|inc(xy>>>8)<<8; break;
 case 0x25: xy=xy&0xFF|dec(xy>>>8)<<8; break;
 case 0x26: xy=xy&0xFF|imm8()<<8; break;
 case 0x2C: xy=xy&0xFF00|inc(xy&0xFF); break;
 case 0x2D: xy=xy&0xFF00|dec(xy&0xFF); break;
 case 0x2E: xy=xy&0xFF00|imm8(); break;
 case 0x34: {int a,v=inc(env.mem(a=getd(xy))); ticks+=4; env.mem(a,v); ticks+=3;} break;
 case 0x35: {int a,v=dec(env.mem(a=getd(xy))); ticks+=4; env.mem(a,v); ticks+=3;} break;
 case 0x36: {int a=xy+(byte)env.mem(PC)&0xFFFF; ticks+=3;
    int v=env.mem(PC+1&0xFFFF); ticks+=5;
    env.mem(a,v); PC=PC+2&0xFFFF; ticks+=3;} break;
 case 0x3C: A=inc(A); break;
 case 0x3D: A=dec(A); break;
 case 0x3E: A=imm8(); break;
 case 0x20: jr(Fr!=0); break;
 case 0x28: jr(Fr==0); break;
 case 0x30: jr((Ff&0x100)==0); break;
 case 0x38: jr((Ff&0x100)!=0); break;
 case 0x07: {int a=A<<1|A>>>7; f_h0n0_c35(a); A=a&0xFF;} break;
 case 0x0F: {int a=A>>>1; f_h0n0_c35(a|A<<8); A=a|A<<7&0xFF;} break;
 case 0x17: {int a=A<<1; A=a&0xFF|Ff>>>8&1; f_h0n0_c35(a);} break;
 case 0x1F: {int a=A; A=(a|Ff&0x100)>>>1; f_h0n0_c35(A|a<<8);} break;
 case 0x27: daa(); break;
 case 0x2F: cpl(); break;
 case 0x37: scf_ccf(0x100); break;
 case 0x3F: scf_ccf(~Ff&0x100); break;
// case 0x40: break;
 case 0x41: B=C; break;
 case 0x42: B=D; break;
 case 0x43: B=E; break;
 case 0x44: B=xy>>>8; break;
 case 0x45: B=xy&0xFF; break;
 case 0x46: B=env.mem(getd(xy)); ticks+=3; break;
 case 0x47: B=A; break;
 case 0x48: C=B; break;
// case 0x49: break;
 case 0x4A: C=D; break;
 case 0x4B: C=E; break;
 case 0x4C: C=xy>>>8; break;
 case 0x4D: C=xy&0xFF; break;
 case 0x4E: C=env.mem(getd(xy)); ticks+=3; break;
 case 0x4F: C=A; break;
 case 0x50: D=B; break;
 case 0x51: D=C; break;
// case 0x52: break;
 case 0x53: D=E; break;
 case 0x54: D=xy>>>8; break;
 case 0x55: D=xy&0xFF; break;
 case 0x56: D=env.mem(getd(xy)); ticks+=3; break;
 case 0x57: D=A; break;
 case 0x58: E=B; break;
 case 0x59: E=C; break;
 case 0x5A: E=D; break;
// case 0x5B: break;
 case 0x5C: E=xy>>>8; break;
 case 0x5D: E=xy&0xFF; break;
 case 0x5E: E=env.mem(getd(xy)); ticks+=3; break;
 case 0x5F: E=A; break;
 case 0x60: xy=xy&0xFF|B<<8; break;
 case 0x61: xy=xy&0xFF|C<<8; break;
 case 0x62: xy=xy&0xFF|D<<8; break;
 case 0x63: xy=xy&0xFF|E<<8; break;
// case 0x64: break;
 case 0x65: xy=xy&0xFF|(xy&0xFF)<<8; break;
 case 0x66: HL=HL&0xFF|env.mem(getd(xy))<<8; ticks+=3; break;
 case 0x67: xy=xy&0xFF|A<<8; break;
 case 0x68: xy=xy&0xFF00|B; break;
 case 0x69: xy=xy&0xFF00|C; break;
 case 0x6A: xy=xy&0xFF00|D; break;
 case 0x6B: xy=xy&0xFF00|E; break;
 case 0x6C: xy=xy&0xFF00|xy>>>8; break;
// case 0x6D: break;
 case 0x6E: HL=HL&0xFF00|env.mem(getd(xy)); ticks+=3; break;
 case 0x6F: xy=xy&0xFF00|A; break;
 case 0x70: env.mem(getd(xy),B); ticks+=3; break;
 case 0x71: env.mem(getd(xy),C); ticks+=3; break;
 case 0x72: env.mem(getd(xy),D); ticks+=3; break;
 case 0x73: env.mem(getd(xy),E); ticks+=3; break;
 case 0x74: env.mem(getd(xy),HL>>>8); ticks+=3; break;
 case 0x75: env.mem(getd(xy),HL&0xFF); ticks+=3; break;
 case 0x76: halt(); break;
 case 0x77: env.mem(getd(xy),A); ticks+=3; break;
 case 0x78: A=B; break;
 case 0x79: A=C; break;
 case 0x7A: A=D; break;
 case 0x7B: A=E; break;
 case 0x7C: A=xy>>>8; break;
 case 0x7D: A=xy&0xFF; break;
 case 0x7E: A=env.mem(getd(xy)); ticks+=3; break;
// case 0x7F: break;
 case 0x80: add(B); break;
 case 0x81: add(C); break;
 case 0x82: add(D); break;
 case 0x83: add(E); break;
 case 0x84: add(xy>>>8); break;
 case 0x85: add(xy&0xFF); break;
 case 0x86: add(env.mem(getd(xy))); ticks+=3; break;
 case 0x87: add(A); break;
 case 0x88: adc(B); break;
 case 0x89: adc(C); break;
 case 0x8A: adc(D); break;
 case 0x8B: adc(E); break;
 case 0x8C: adc(xy>>>8); break;
 case 0x8D: adc(xy&0xFF); break;
 case 0x8E: adc(env.mem(getd(xy))); ticks+=3; break;
 case 0x8F: adc(A); break;
 case 0x90: sub(B); break;
 case 0x91: sub(C); break;
 case 0x92: sub(D); break;
 case 0x93: sub(E); break;
 case 0x94: sub(xy>>>8); break;
 case 0x95: sub(xy&0xFF); break;
 case 0x96: sub(env.mem(getd(xy))); ticks+=3; break;
 case 0x97: sub(A); break;
 case 0x98: sbc(B); break;
 case 0x99: sbc(C); break;
 case 0x9A: sbc(D); break;
 case 0x9B: sbc(E); break;
 case 0x9C: sbc(xy>>>8); break;
 case 0x9D: sbc(xy&0xFF); break;
 case 0x9E: sbc(env.mem(getd(xy))); ticks+=3; break;
 case 0x9F: sbc(A); break;
 case 0xA0: and(B); break;
 case 0xA1: and(C); break;
 case 0xA2: and(D); break;
 case 0xA3: and(E); break;
 case 0xA4: and(xy>>>8); break;
 case 0xA5: and(xy&0xFF); break;
 case 0xA6: and(env.mem(getd(xy))); ticks+=3; break;
 case 0xA7: and(A); break;
 case 0xA8: xor(B); break;
 case 0xA9: xor(C); break;
 case 0xAA: xor(D); break;
 case 0xAB: xor(E); break;
 case 0xAC: xor(xy>>>8); break;
 case 0xAD: xor(xy&0xFF); break;
 case 0xAE: xor(env.mem(getd(xy))); ticks+=3; break;
 case 0xAF: xor(A); break;
 case 0xB0: or(B); break;
 case 0xB1: or(C); break;
 case 0xB2: or(D); break;
 case 0xB3: or(E); break;
 case 0xB4: or(xy>>>8); break;
 case 0xB5: or(xy&0xFF); break;
 case 0xB6: or(env.mem(getd(xy))); ticks+=3; break;
 case 0xB7: or(A); break;
 case 0xB8: cp(B); break;
 case 0xB9: cp(C); break;
 case 0xBA: cp(D); break;
 case 0xBB: cp(E); break;
 case 0xBC: cp(xy>>>8); break;
 case 0xBD: cp(xy&0xFF); break;
 case 0xBE: cp(env.mem(getd(xy))); ticks+=3; break;
 case 0xBF: cp(A); break;
 case 0xDD:
 case 0xFD: c0=c; continue;
 case 0xCB: group_xy_cb(xy); break;
 case 0xED: group_ed(); break;
 case 0xC0: ticks++; if(Fr!=0) ir=PC=pop(); break;
 case 0xC2: jp(Fr!=0); break;
 case 0xC4: call(Fr!=0); break;
 case 0xC8: ticks++; if(Fr==0) ir=PC=pop(); break;
 case 0xCA: jp(Fr==0); break;
 case 0xCC: call(Fr==0); break;
 case 0xD0: ticks++; if((Ff&0x100)==0) ir=PC=pop(); break;
 case 0xD2: jp((Ff&0x100)==0); break;
 case 0xD4: call((Ff&0x100)==0); break;
 case 0xD8: ticks++; if((Ff&0x100)!=0) ir=PC=pop(); break;
 case 0xDA: jp((Ff&0x100)!=0); break;
 case 0xDC: call((Ff&0x100)!=0); break;
 case 0xE0: ticks++; if((flags()&FP)==0) ir=PC=pop(); break;
 case 0xE2: jp((flags()&FP)==0); break;
 case 0xE4: call((flags()&FP)==0); break;
 case 0xE8: ticks++; if((flags()&FP)!=0) ir=PC=pop(); break;
 case 0xEA: jp((flags()&FP)!=0); break;
 case 0xEC: call((flags()&FP)!=0); break;
 case 0xF0: ticks++; if((Ff&FS)==0) ir=PC=pop(); break;
 case 0xF2: jp((Ff&FS)==0); break;
 case 0xF4: call((Ff&FS)==0); break;
 case 0xF8: ticks++; if((Ff&FS)!=0) ir=PC=pop(); break;
 case 0xFA: jp((Ff&FS)!=0); break;
 case 0xFC: call((Ff&FS)!=0); break;
 case 0xC1: {int v=pop(); B=v>>8; C=v&0xFF;} break;
 case 0xC5: push(B<<8|C); break;
 case 0xD1: {int v=pop(); D=v>>8; E=v&0xFF;} break;
 case 0xD5: push(D<<8|E); break;
 case 0xE1: xy=pop(); break;
 case 0xE5: push(xy); break;
 case 0xF1: af(pop()); break;
 case 0xF5: push(A<<8|flags()); break;
 case 0xC3: PC=imm16(); break;
 case 0xC6: add(imm8()); break;
 case 0xCE: adc(imm8()); break;
 case 0xD6: sub(imm8()); break;
 case 0xDE: sbc(imm8()); break;
 case 0xE6: and(imm8()); break;
 case 0xEE: xor(imm8()); break;
 case 0xF6: or(imm8()); break;
 case 0xFE: cp(imm8()); break;
 case 0xC9: ir=PC=pop(); break;
 case 0xCD: call(true); break;
 case 0xD3: env.out(imm8()|A<<8,A); ticks+=4; break;
 case 0xDB: A=env.in(imm8()|A<<8); ticks+=4; break;
 case 0xD9: exx(); break;
 case 0xE3: {int v=env.mem16(SP); ticks+=7;
    env.mem16(SP,xy); xy=v;} ticks+=8; break;
 case 0xE9: PC=xy; break;
 case 0xEB: {int v=HL; HL=D<<8|E; D=v>>>8; E=v&0xFF;} break;
 case 0xF3: IFF=0; break;
 case 0xFB: IFF=3; break;
 case 0xF9: SP=xy; ticks+=2; break;
 case 0xC7:
 case 0xCF:
 case 0xD7:
 case 0xDF:
 case 0xE7:
 case 0xEF:
 case 0xF7:
 case 0xFF: push(PC); PC=c-199; break;
// -------------- >8
            }
            if(c0==0xDD) IX = xy; else IY = xy;
            break;
        }
    }

    private void group_ed()
    {
        int c = env.m1(PC); PC = PC+1 & 0xFFFF;
        ticks += 4; R++;
        switch(c) {
// -------------- >8
 case 0x47: I=A; ticks++; break;
 case 0x4F: r(A); ticks++; break;
 case 0x57: ld_a_ir(I); break;
 case 0x5F: ld_a_ir(r()); break;
 case 0x67: rrd(); break;
 case 0x6F: rld(); break;
 case 0x40: {int v=env.in(B<<8|C); B=v; f_szh0n0p(v);} ticks+=4; break;
 case 0x41: env.out(B<<8|C,B); ticks+=4; break;
 case 0x48: {int v=env.in(B<<8|C); C=v; f_szh0n0p(v);} ticks+=4; break;
 case 0x49: env.out(B<<8|C,C); ticks+=4; break;
 case 0x50: {int v=env.in(B<<8|C); D=v; f_szh0n0p(v);} ticks+=4; break;
 case 0x51: env.out(B<<8|C,D); ticks+=4; break;
 case 0x58: {int v=env.in(B<<8|C); E=v; f_szh0n0p(v);} ticks+=4; break;
 case 0x59: env.out(B<<8|C,E); ticks+=4; break;
 case 0x60: {int v=env.in(B<<8|C); HL=HL&0xFF|v<<8; f_szh0n0p(v);} ticks+=4; break;
 case 0x61: env.out(B<<8|C,HL>>>8); ticks+=4; break;
 case 0x68: {int v=env.in(B<<8|C); HL=HL&0xFF00|v; f_szh0n0p(v);} ticks+=4; break;
 case 0x69: env.out(B<<8|C,HL&0xFF); ticks+=4; break;
 case 0x70: f_szh0n0p(env.in(B<<8|C)); ticks+=4; break;
 case 0x71: env.out(B<<8|C,0); ticks+=4; break;
 case 0x78: {int v=env.in(B<<8|C); A=v; f_szh0n0p(v);} ticks+=4; break;
 case 0x79: env.out(B<<8|C,A); ticks+=4; break;
 case 0x42: sbc_hl(B<<8|C); break;
 case 0x4A: adc_hl(B<<8|C); break;
 case 0x43: env.mem16(imm16(),B<<8|C); ticks+=6; break;
 case 0x4B: {int v=env.mem16(imm16()); B=v>>>8; C=v&0xFF;} ticks+=6; break;
 case 0x52: sbc_hl(D<<8|E); break;
 case 0x5A: adc_hl(D<<8|E); break;
 case 0x53: env.mem16(imm16(),D<<8|E); ticks+=6; break;
 case 0x5B: {int v=env.mem16(imm16()); D=v>>>8; E=v&0xFF;} ticks+=6; break;
 case 0x62: sbc_hl(HL); break;
 case 0x6A: adc_hl(HL); break;
 case 0x63: env.mem16(imm16(),HL); ticks+=6; break;
 case 0x6B: HL=env.mem16(imm16()); ticks+=6; break;
 case 0x72: sbc_hl(SP); break;
 case 0x7A: adc_hl(SP); break;
 case 0x73: env.mem16(imm16(),SP); ticks+=6; break;
 case 0x7B: SP=env.mem16(imm16()); ticks+=6; break;
 case 0x44:
 case 0x4C:
 case 0x54:
 case 0x5C:
 case 0x64:
 case 0x6C:
 case 0x74:
 case 0x7C: {int a=A; A=0; sub(a);} break;
 case 0x45:
 case 0x4D:
 case 0x55:
 case 0x5D:
 case 0x65:
 case 0x6D:
 case 0x75:
 case 0x7D: IFF|=IFF>>1; PC=pop(); break;
 case 0x46:
 case 0x4E:
 case 0x56:
 case 0x5E:
 case 0x66:
 case 0x6E:
 case 0x76:
 case 0x7E: IM = (byte)(c>>3&3); break;
 case 0xA0: ldir(1,false); break;
 case 0xA8: ldir(-1,false); break;
 case 0xB0: ldir(1,true); break;
 case 0xB8: ldir(-1,true); break;
 case 0xA1: cpir(1,false); break;
 case 0xA9: cpir(-1,false); break;
 case 0xB1: cpir(1,true); break;
 case 0xB9: cpir(-1,true); break;
 case 0xA2:
 case 0xA3:
 case 0xAA:
 case 0xAB:
 case 0xB2:
 case 0xB3:
 case 0xBA:
 case 0xBB: inir_otir(c); break;
// -------------- >8
        default: //System.out.println(PC+": Not emulated ED/"+c);
        }
    }

    private void group_cb()
    {
        int c = env.m1(PC); PC = PC+1 & 0xFFFF;
        ticks+=4; R++;
        int o = c>>>3 & 7;
        switch(c & 0xC7) {
// -------------- >8
 case 0x00: B=shifter(o,B); break;
 case 0x01: C=shifter(o,C); break;
 case 0x02: D=shifter(o,D); break;
 case 0x03: E=shifter(o,E); break;
 case 0x04: HL=HL&0xFF|shifter(o,HL>>>8)<<8; break;
 case 0x05: HL=HL&0xFF00|shifter(o,HL&0xFF); break;
 case 0x06: {int v=shifter(o,env.mem(HL)); ticks+=4; env.mem(HL,v); ticks+=3;} break;
 case 0x07: A=shifter(o,A); break;
 case 0x40: bit(o,B); break;
 case 0x41: bit(o,C); break;
 case 0x42: bit(o,D); break;
 case 0x43: bit(o,E); break;
 case 0x44: bit(o,HL>>>8); break;
 case 0x45: bit(o,HL&0xFF); break;
 case 0x46: bit(o,env.mem(HL)); Ff=Ff&~F53|ir>>8&F53; ticks+=4; break;
 case 0x47: bit(o,A); break;
 case 0x80: B=B&~(1<<o); break;
 case 0x81: C=C&~(1<<o); break;
 case 0x82: D=D&~(1<<o); break;
 case 0x83: E=E&~(1<<o); break;
 case 0x84: HL&=~(0x100<<o); break;
 case 0x85: HL&=~(1<<o); break;
 case 0x86: {int v=env.mem(HL)&~(1<<o); ticks+=4; env.mem(HL,v); ticks+=3;} break;
 case 0x87: A=A&~(1<<o); break;
 case 0xC0: B=B|1<<o; break;
 case 0xC1: C=C|1<<o; break;
 case 0xC2: D=D|1<<o; break;
 case 0xC3: E=E|1<<o; break;
 case 0xC4: HL|=0x100<<o; break;
 case 0xC5: HL|=1<<o; break;
 case 0xC6: {int v=env.mem(HL)|1<<o; ticks+=4; env.mem(HL,v); ticks+=3;} break;
 case 0xC7: A=A|1<<o; break;
// -------------- >8
        }
    }

    private void group_xy_cb(int xy)
    {
        int pc = PC;
        int a = ir = xy+(byte)env.mem(pc) & 0xFFFF;
        ticks += 3;
        int c = env.mem(pc+1 & 0xFFFF);
        PC = pc+2 & 0xFFFF;
        ticks += 5;
        int v = env.mem(a);
        ticks += 4;

        int o = c>>>3 & 7;
        switch(c&0xC0) {
            case 0x00: v = shifter(o, v); break;
            case 0x40: bit(o, v); Ff=Ff&~F53 | a>>8&F53; return;
            case 0x80: v &= ~(1<<o); break;
            case 0xC0: v |= 1<<o; break;
        }
        env.mem(a, v);
        ticks += 3;
        switch(c&0x07) {
            case 0: B = v; break;
            case 1: C = v; break;
            case 2: D = v; break;
            case 3: E = v; break;
            case 4: HL = HL&0x00FF | v<<8; break;
            case 5: HL = HL&0xFF00 | v; break;
            case 7: A = v; break;
        }
    }

    /* interrupts */

    private byte IFF, IM;
    private boolean halted;

    boolean interrupt(int bus)
    {
        if((IFF&1)==0)
            return false;
        IFF = 0;
        halted = false;
        ticks += 6;
        push(PC);
        switch(IM) {
            case 0: // IM 0
            case 1: // IM 0
                if((bus|0x38)==0xFF) {PC=bus-199; break;}
                /* not emulated */
            case 2: // IM 1
                PC = 0x38; break;
            case 3: // IM 2
                PC = env.mem16(I<<8 | bus);
                ticks += 6;
                break;
        }
        return true;
    }

    void nmi()
    {
        IFF &= 2;
        halted = false;
        push(PC);
        ticks += 4;
        PC = 0x66;
    }

    void reset() {
        halted = false;
        IFF = IM = 0;
        PC = 0;
        SP = 0xFFFF;
        af(0xFFFF);
    }

    // Implementation of abstract methods from Z80ImplBase superclass.
    public byte getA() {return (byte) A;}
    public byte getA2() {return (byte) A_;}
    public byte getB() {return (byte) B;}
    public byte getB2() {return (byte) B_;}
    public byte getC() {return (byte) C;}
    public byte getC2() {return (byte) C_;}
    public byte getD() {return (byte) D;}
    public byte getD2() {return (byte) D_;}
    public byte getE() {return (byte) E;}
    public byte getE2() {return (byte) E_;}
    public byte getF() {return (byte) flags();}
    public byte getF2() {ex_af(); byte f = (byte) flags(); ex_af(); return f;}
    public byte getH() {return (byte) (HL >>> 8);}
    public byte getH2() {return (byte) (HL_ >>> 8);}
    public byte getI() {return (byte) I;}
    public boolean getIFF1() {return (IFF & 0x01) != 0;}
    public boolean getIFF2() {return (IFF & 0x02) != 0;}
    public byte getIM() {return (byte) ((IM == 0) ? IM : IM-1);}
    public short getIX() {return (short) IX;}
    public short getIY() {return (short) IY;}
    public byte getL() {return (byte) HL;}
    public byte getL2() {return (byte) HL_;}
    public short getPC() {return (short) PC;}
    public byte getR() {return (byte) r();}
    public short getSP() {return (short) SP;}

    public void setA(byte value) {A = value & 0xFF;}
    public void setA2(byte value) {A_ = value & 0xFF;}
    public void setB(byte value) {B = value & 0xFF;}
    public void setB2(byte value) {B_ = value & 0xFF;}
    public void setC(byte value) {C = value & 0xFF;}
    public void setC2(byte value) {C_ = value & 0xFF;}
    public void setD(byte value) {D = value & 0xFF;}
    public void setD2(byte value) {D_ = value & 0xFF;}
    public void setE(byte value) {E = value & 0xFF;}
    public void setE2(byte value) {E_ = value & 0xFF;}
    public void setF(byte value) {flags(value & 0xFF);}
    public void setF2(byte value) {ex_af(); flags(value & 0xFF); ex_af();}
    public void setH(byte value) {HL = (HL & 0xFF) | ((value & 0xFF) << 8);}
    public void setH2(byte value) {HL_ = (HL_ & 0xFF) | ((value & 0xFF) << 8);}
    public void setI(byte value) {I = value & 0xFF;}
    public void setIFF1(boolean value) {if (value) IFF |= 0x01; else IFF &= 0xFE;} 
    public void setIFF2(boolean value) {if (value) IFF |= 0x02; else IFF &= 0xFD;}
    public void setIM(byte value) {value &= 3; if (value != 0) value++; IM = (byte) value;}
    public void setIX(short value) {IX = value & 0xFFFF;}
    public void setIY(short value) {IY = value & 0xFFFF;}
    public void setL(byte value) {HL = (HL & 0xFF00) | (value & 0xFF);}
    public void setL2(byte value) {HL_ = (HL_ & 0xFF00) | (value & 0xFF);}
    public void setPC(short value) {PC = value & 0xFFFF;}
    public void setR(byte value) {r(value & 0xFF);}
    public void setSP(short value) {SP = value & 0xFFFF;}
    
    public void processInstruction() {
        halted = false;
        ticks_limit = 0;
        ticks = 0;
        execute();
    }

    public long getCycles() {return 0;}
}
